package com.mineoj.controller;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mineoj.common.BaseResponse;
import com.mineoj.common.DeleteRequest;
import com.mineoj.common.ErrorCode;
import com.mineoj.common.ResultUtils;
import com.mineoj.constant.FileConstant;
import com.mineoj.exception.BusinessException;
import com.mineoj.exception.ThrowUtils;
import com.mineoj.manager.CosManager;
import com.mineoj.model.dto.file.FileMessageQueryRequest;
import com.mineoj.model.dto.file.UploadFileRequest;
import com.mineoj.model.entity.FileMessage;
import com.mineoj.model.entity.FileMessage;
import com.mineoj.model.entity.FileMessage;
import com.mineoj.model.entity.User;
import com.mineoj.model.enums.FileUploadBizEnum;
import com.mineoj.model.vo.FileMessageVO;
import com.mineoj.service.FileMessageService;
import com.mineoj.service.UserService;
import com.mineoj.utils.AliOssUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.UUID;
import org.springframework.http.MediaType;

@RestController
@RequestMapping("/file")
@Slf4j
public class FileController {

    @Autowired
    private AliOssUtil aliOssUtil;

    @Resource
    private UserService userService;

    @Resource
    private FileMessageService fileMessageService;


    /**
     * 文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public BaseResponse<String> uploadFile(@RequestPart("file") MultipartFile file, UploadFileRequest uploadFileRequest, HttpServletRequest request){
        // 校验
        String biz = uploadFileRequest.getBiz();
        FileUploadBizEnum fileUploadBizEnum = FileUploadBizEnum.getEnumByValue(biz);
        if (fileUploadBizEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        fileMessageService.validFile(file, fileUploadBizEnum);

        User loginUser = userService.getLoginUser(request);


        try {
            //原始文件名
            String originalFilename = file.getOriginalFilename();
            //截取原始文件名的后缀
            String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
            String objectName = UUID.randomUUID().toString() + extension;

            //文件请求路径
            String filePath = aliOssUtil.upload(file.getBytes(),objectName);

           // 保存到数据库
            FileMessage fileMessage = new FileMessage();
            fileMessage.setName(originalFilename);
            fileMessage.setFile(objectName);
            fileMessage.setUserId(loginUser.getId());
            fileMessage.setSize((double) file.getSize() / 1024);
            fileMessage.setType(file.getContentType());
            fileMessage.setPath(filePath);
            fileMessageService.saveFile(fileMessage, loginUser, fileUploadBizEnum);

            // 返回可访问地址
            return ResultUtils.success(FileConstant.COS_HOST + filePath);
        } catch (IOException e) {

            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "上传失败");
        }

    }

    /**
     * 文件下载
     * @param id 文件记录ID
     */
    @GetMapping("/download/{id}")
    public ResponseEntity<byte[]> downloadFile(@PathVariable Long id, HttpServletRequest request) {
        // 获取登录用户
        User loginUser = userService.getLoginUser(request);

        // 查询文件记录
        FileMessage fileMessage = fileMessageService.getById(id);
        if (fileMessage == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "文件不存在");
        }


        // 从OSS下载文件
        byte[] fileData = aliOssUtil.download(fileMessage.getFile());
        if (fileData == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "文件下载失败");
        }

        try {
            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            // 1.内容类型（从数据库记录获取）
            headers.setContentType(MediaType.parseMediaType(
                    fileMessage.getType() != null ?
                            fileMessage.getType() :
                            "application/octet-stream"));

            // 2.文件下载头（处理中文文件名编码）
            String encodedFileName = URLEncoder.encode(
                            fileMessage.getName(),
                            StandardCharsets.UTF_8.toString())
                    .replaceAll("\\+", "%20");

            headers.setContentDisposition(ContentDisposition.builder("attachment")
                    .filename(encodedFileName)
                    .build());

            return new ResponseEntity<>(fileData, headers, HttpStatus.OK);
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "文件下载异常");
        }
    }


    /**
     * 删除
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteFileMessage(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User user = userService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断是否存在
        FileMessage oldFileMessage = fileMessageService.getById(id);
        ThrowUtils.throwIf(oldFileMessage == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可删除
        if (!oldFileMessage.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean b = fileMessageService.removeById(id);
        return ResultUtils.success(b);
    }


    /**
     * 根据 id 获取
     *
     * @param id
     * @return FileMessageVO
     */
    @GetMapping("/get/vo")
    public BaseResponse<FileMessageVO> getFileMessageVOById(long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        FileMessage fileMessage = fileMessageService.getById(id);
        if (fileMessage == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        return ResultUtils.success(fileMessageService.getFileMessageVO(fileMessage, request));
    }

    /**
     * 分页获取列表（封装类）
     *
     * @param fileMessageQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<FileMessageVO>> listFileMessageVOByPage(@RequestBody FileMessageQueryRequest fileMessageQueryRequest,
                                                                     HttpServletRequest request) {
        long current = fileMessageQueryRequest.getCurrent();
        long size = fileMessageQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        Page<FileMessage> fileMessagePage = fileMessageService.page(new Page<>(current, size),
                fileMessageService.getQueryWrapper(fileMessageQueryRequest));
        return ResultUtils.success(fileMessageService.getFileMessageVOPage(fileMessagePage, request));
    }

    /**
     * 分页获取当前用户创建的资源列表
     *
     * @param fileMessageQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<FileMessageVO>> listMyFileMessageVOByPage(@RequestBody FileMessageQueryRequest fileMessageQueryRequest,
                                                                 HttpServletRequest request) {
        if (fileMessageQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        fileMessageQueryRequest.setUserId(loginUser.getId());
        long current = fileMessageQueryRequest.getCurrent();
        long size = fileMessageQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        Page<FileMessage> fileMessagePage = fileMessageService.page(new Page<>(current, size),
                fileMessageService.getQueryWrapper(fileMessageQueryRequest));
        return ResultUtils.success(fileMessageService.getFileMessageVOPage(fileMessagePage, request));
    }



}
